package com.jing.yao.modules.user.service.impl;

import com.jing.yao.bean.KeyValue;
import com.jing.yao.cache.CacheHelper;
import com.jing.yao.cache.RedisKeyEnum;
import com.jing.yao.code.UserCode;
import com.jing.yao.component.constants.BaseOperationEnum;
import com.jing.yao.component.mapper.YaoBaseMapper;
import com.jing.yao.constant.Enabled;
import com.jing.yao.exception.BusinessException;
import com.jing.yao.exception.BusinessExceptionBuilder;
import com.jing.yao.modules.role.dao.UserRoleMapper;
import com.jing.yao.modules.role.dao.entity.UserRoleEntity;
import com.jing.yao.modules.user.dao.UserMapper;
import com.jing.yao.modules.user.dao.entity.UserEntity;
import com.jing.yao.modules.user.service.UserService;
import com.jing.yao.utils.CryptoUtils;
import com.jing.yao.utils.UserInfoUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户service的实现类
 *
 * @author lirui
 * @since 2020-06-13
 */
@Service
@RefreshScope
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Value("${bms.user.default.password:123456}")
    private String defaultPwd;

    @Autowired
    private CacheHelper cacheHelper;

    @Override
    public YaoBaseMapper<UserEntity> getMapper() {
        return userMapper;
    }

    /**
     * 操作前判断
     *
     * @param entity        前端传递的对象
     * @param operationEnum 操作类型
     * @throws BusinessException
     */
    @Override
    public void processBeforeOperation(UserEntity entity, BaseOperationEnum operationEnum) throws BusinessException {

        switch (operationEnum) {
            case INSERT:
                //用户名
                String username = entity.getUsername();
                LambdaQueryWrapper<UserEntity> wrappers = Wrappers.lambdaQuery();
                wrappers.eq(UserEntity::getUsername, username);
                UserEntity userEntity = getMapper().selectOne(wrappers);
                if (userEntity != null) {
                    throw BusinessExceptionBuilder.build(UserCode.USER_EXIST);
                }

                //初始化密码
                entity.setPassword(UserInfoUtils.getPassword(defaultPwd));
                entity.setAccountLocked(Enabled.NO.getValue());
                entity.setAccountNonExpired(Enabled.YES.getValue());
                entity.setCredentialsNonExpired(Enabled.YES.getValue());
        }

    }

    /**
     * 根据用户名查询用户
     *
     * @param username
     * @return
     */
    @Override
    public UserEntity findByUsername(String username) {
        LambdaQueryWrapper<UserEntity> queryWrapper = Wrappers.<UserEntity>lambdaQuery().eq(UserEntity::getUsername, username);
        UserEntity userEntity = userMapper.selectOne(queryWrapper);
        //当用户不存在时，抛出异常
        if (userEntity == null) {
            throw BusinessExceptionBuilder.build(UserCode.USER_NO_EXIST);
        }

        return userEntity;
    }

    /**
     * 给用户分配角色
     *
     * @param username
     * @param roles
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userRole(String username, List<String> roles) {

        //删除用户对应的角色
        LambdaQueryWrapper<UserRoleEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserRoleEntity::getUsername, username);
        userRoleMapper.delete(wrapper);

        if (CollectionUtils.isEmpty(roles)) {
            return;
        }

        List<UserRoleEntity> userRoleEntities = roles.stream().map(role -> {
            UserRoleEntity userRoleEntity = new UserRoleEntity();
            userRoleEntity.setRoleCode(role);
            userRoleEntity.setUsername(username);
            return userRoleEntity;
        }).collect(Collectors.toList());

        //批量插入
        userRoleMapper.insertBatch(userRoleEntities);
    }

    @Override
    public void resetPwd(Long id) {

        String password = UserInfoUtils.getPassword(defaultPwd);

        UserEntity userEntity = userMapper.selectById(id);
        if (userEntity == null) {
            throw BusinessExceptionBuilder.build(UserCode.USER_NO_EXIST);
        }
        userEntity.setPassword(password);

        userMapper.updateById(userEntity);
        //清除登录标识
        clearUserLogin(userEntity.getUsername());
    }

    /**
     * 清除登录标识
     *
     * @param username
     */
    private void clearUserLogin(String username) {
        //删除登录标识

        String token = cacheHelper.hashGetString(RedisKeyEnum.TOKEN_JWT_USER.getKey(), username);

        //删除用户名和token对应关系
        cacheHelper.hashDel(RedisKeyEnum.TOKEN_JWT_USER.getKey(), username);
        //删除token与私钥对应关系
        if (StringUtils.isNotBlank(token)) {
            cacheHelper.stringSetExpire(RedisKeyEnum.TOKEN_JWT_EXPIRE.getKey() + token, Enabled.YES.getValue().toString(), 2, TimeUnit.HOURS);

        }
    }

    @Override
    public void updatePwd(String username, String newPassword, String inputOldPassword) {
        //查询用户在库中密码
        UserEntity user = findByUsername(username);
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

        //计算输入的密码
        String oldPassword = bCryptPasswordEncoder.encode(inputOldPassword);

        //当原密码输错时
        if (!StringUtils.equals(user.getPassword(), oldPassword)) {
            throw BusinessExceptionBuilder.build(UserCode.USER_OLD_PASSWORD_ERROR);
        }

        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$";
        String inputPassword = "";
        try {
            inputPassword = CryptoUtils.desEncrypt(newPassword);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!inputPassword.matches(regex)) {
            throw BusinessExceptionBuilder.build(UserCode.USER_PASSWORD_PATTERN_ERROR);
        }
        String password = bCryptPasswordEncoder.encode(newPassword);

        //设置新密码
        user.setPassword(password);
        userMapper.updateById(user);

        //清除登录标识
        clearUserLogin(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserStatus(String userName, Integer status, String updateBy) {
        UserEntity userEntity = findByUsername(userName);
        userEntity.setEnabled(status);
        userMapper.updateById(userEntity);
        if (Enabled.NO.getValue().equals(status)) {
            clearUserLogin(userName);
        }
    }

    @Override
    public List<KeyValue> getUserList() {
        LambdaQueryWrapper<UserEntity> queryWrapper = Wrappers.<UserEntity>lambdaQuery().eq(UserEntity::getEnabled, 1);
        List<UserEntity> userEntities = userMapper.selectList(queryWrapper);
        List<KeyValue> list = userEntities.stream().map(entity -> {
            KeyValue keyValue = new KeyValue();
            keyValue.setId(entity.getUsername());
            keyValue.setText(entity.getNickname());
            return keyValue;
        }).collect(Collectors.toList());
        return list;
    }


}
